#include <memory>
#include <chrono>
#include <thread>
#include <vector>
#include <iostream>

#include "log.h"

/// @brief 性能测试接口
/// @param log_name 日志器名称
/// @param thread_num 线程数量
/// @param log_num 日志数量
/// @param log_size 单条日志大小
void bench(const std::string& log_name, size_t thread_num, size_t log_num, size_t log_size){
	// 1.得到日志器
	mylog::Logger::ptr logger = mylog::GetLogger(log_name);
	if (logger.get() == nullptr)return;
	
	// 2.创建日志消息，分配每个线程输出的日志数量
	std::string msg(log_size - 1, 'A'); // 这里-1是为了在其后面添加\n，便于日志输出结果的观察
	size_t thr_per_num = log_num / thread_num;
	std::cout << "日志写入总条数：" << log_num << std::endl;
	std::cout << "每条日志的大小：" << log_size << std::endl;
	std::cout << "线程数目：" << thread_num << std::endl;
	std::cout << "每个线程的写入条数：" << thr_per_num << std::endl;
	std::cout << "---------------------------------------------------" << std::endl;
	// 3.创建线程
	std::vector<std::thread> threads;		// 线程对象数组
	std::vector<double> cost(thread_num);	// 每个线程消耗的时间
	for (int i = 0; i < thread_num; i++)
	{
		threads.emplace_back([&, i]() {
			// 4.开始计时
			auto begin = std::chrono::high_resolution_clock::now();
			// 5.进行日志输出
			for (int j = 0; j < thr_per_num; j++)
			{
				logger->Fatal("%s\n", msg.c_str());
			}
			// 6.结束计时
			auto end = std::chrono::high_resolution_clock::now();
			std::chrono::duration<double> time_span = end - begin;
			// 将消耗时间放入cost数组中
			cost[i] = time_span.count();
			std::cout << "线程：" << i << ", 写入消耗时间：" << time_span.count() << std::endl;
			});
	}
	// 回收线程
	for (int i = 0; i < thread_num; i++)
	{
		if(threads[i].joinable()) threads[i].join();
	}

	// 7.计算：每秒输出日志数，每秒输出日志大小
	// 消耗的总时间是cost数组中的最大值，因为线程是并发执行的
	double max_time = cost[0];
	for (size_t i = 1; i < cost.size(); i++)
	{
		max_time = cost[i] > max_time ? cost[i] : max_time;
	}
	// 每秒输出的日志数目
	size_t num_per_sec = log_num / max_time;
	// 每秒输出的字节大小(KB)
	size_t size_per_sec = (log_num * log_size) / (max_time * 1024);

	// 8.将计算结果输出
	std::cout << "---------------------------------------------------" << std::endl;
	std::cout << "消耗总时间：" << max_time << std::endl;
	std::cout << "每秒输出的日志数目" << num_per_sec << "/s" << std::endl;
	std::cout << "每秒输出的字节大小" << size_per_sec << "KB" << std::endl;
}


/// @brief 同步日志器性能测试
/// @param thread_num 线程数目
void sync_bench(size_t thread_num = 1)
{
	// 1.建造日志器对象
	mylog::GlobalLoggerBuilder g_builder;
	g_builder.BuildName("Sync_logger");
	g_builder.BuildType(mylog::LoggerType::Sync_Logger);
	g_builder.BuildLevel(mylog::LogLevel::Level::DEBUG);
	g_builder.BuildFormatter("%m");
	// 设置落地方向
	g_builder.AddLogSink<mylog::FileSink>("./logfile/syncfile.mylog");
	g_builder.Build();
	bench("Sync_logger", thread_num, 1000000, 100);
}


/// @brief 异步日志器性能测试
/// @param thread_num 线程数目
void async_bench(size_t thread_num = 1)
{
	// 1.建造日志器对象
	mylog::GlobalLoggerBuilder g_builder;
	g_builder.BuildName("Async_logger");
	g_builder.BuildType(mylog::LoggerType::Async_Logger);
	g_builder.BuildLevel(mylog::LogLevel::Level::DEBUG);
	g_builder.BuildFormatter("[%d{%Y-%m-%d %H:%M:%S}][%p][%c][%t][%f:%l]%T%m%n");
	// 开启非安全模式，在测试中将实际异步落地消耗的时间排除
	g_builder.BuildEnableUnSafe();
	// 设置落地方向
	g_builder.AddLogSink<mylog::FileSink>("./logfile/asyncfile.mylog");
	g_builder.Build();
	bench("Async_logger", thread_num, 1000000, 100);
}

int main()
{
	// 同步单线程测试
	// sync_bench(1);

	// 同步四线程测试
	// sync_bench(4);

	// 异步单线程测试
	// async_bench(1);

	// 异步四线程测试
	async_bench(4);
	return 0;
}